package org.NooLab.openNLP;



import java.util.Map;
 



import org.NooLab.utilities.datatypes.IndexDistance;
import org.NooLab.utilities.datatypes.IndexedDistances;
import org.NooLab.utilities.datatypes.ValuePair;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.files.PathFinder;
import org.NooLab.utilities.logging.LogControl;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.resources.ResourceLoader;
 
import org.NooLab.structures.AppInstanceAbstract;
import org.NooLab.structures.ArgumentsCliReaderAbstract;
import org.NooLab.structures.ArgumentsIntf;
import org.NooLab.structures.InstanceProcessControlIntf;
import org.NooLab.structures.ArgumentsPublicIntf;

import org.NooLab.openNLP.app.DataStreamProviderIntf;
import org.NooLab.openNLP.app.LinguistProperties;
import org.NooLab.openNLP.app.PersistenceSettings;
import org.NooLab.openNLP.app.up.NLPStartup;
import org.NooLab.openNLP.app.up.IniProperties;
 



/*
  
command line arguments
  
-homedir:"D:/data/iTexx/app/ling" 

-flavor:pos | parser 

-onCompletion:exit
-context:itexx
-comm: in-7208,out-7210
-appsecret: adkhf-23487asdf-3487sdfr-324
-name:NooLabNLP
-loglevel:2
 */

/**
 *
 	external dependencies for re-compilation

		1. NooLabUtilities as external jar
		2. NooLabiTexxCommBox (NooLabUtilities as external jar)
		3. NooLabiTexxStructures (NooLabiTexxCommBox as external jar)
		4. NooLabiTexxStructures as external jar
    then always refresh before rebuild! 
 *       
 * 
 * if running in iTexx, iTexx is controlling whether to start the Astor from scratch
 * or whether to resume = loading a previously created Astor SOM (default).
 * iTexx always assumes resume=true
 * 
 * If there is no flag or no astor base model it starts from the scratch, else
 * it reloads the existing one
 * 
 * Astor-SOMs (as well as others) write an entry into a small xml status file
 * whether they COULD be started as a resume  
 * 
 * important place:
 *    class BSTparse :: collectResults2Set()
 *    class SearchTermsPreparation
 *
 * Technical remark:
 * it is very important to start the JVM with the following parameters !!
 * 
   -Xmx1140m
   -XX:+ExplicitGCInvokesConcurrent
   -XX:+UseConcMarkSweepGC

 */
public class NLP {


	private App nlpapp;
	
	//=========================================================================
	public static void main(String[] args) {

		try {
			
			System.out.println("Starting...");
			
			new NLP(args);
				
			System.out.println("Started.");
			PrintLog.Delay(15000);
			
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		


	}


	
	//=========================================================================

	
	private NLP(String[] args){
		
		try {
			
			NLPStartup.setApplicationID("nlpapp", this.getClass());

			(nlpapp = new App( 0, (new Arguments()).parse(args), this.getClass())).go();
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		 
	}


	public void close() {
		nlpapp.close();
		
	}
}
// ----------------------------------------------------------------------------








@SuppressWarnings("rawtypes")
class App{
	
	public String processName;
	public String secret;

	
	LinguisticProcessorInstance lingInstance;
	 
	ArgumentsPublicIntf arguments;
	
	PrintLog out ;
	DFutils fileutil = new DFutils();
	boolean instanceStopped;

	// ========================================================================
	
	public App( int as_service, ArgumentsPublicIntf args, Class pubClass) {	
	
		String fname = "" ; 
		
		arguments = args;
		
		// use LogControl to control output of log messages
		LogControl.globeScope = 2; // 1=local definitions  default = 2
		LogControl.Level = 2 ;     // the larger the more detailed logging... (could be really verbose!)

		out = new PrintLog(2, true) ;
		out.setPrefix("[nooNLP]") ;
		
		
		try {
			String lastCfgFile ="" ;
			
			NLPStartup.setProjectSpaceLabel( arguments.getProjectName()) ;
			NLPStartup.setLastProjectName(arguments.getProjectName());
			
			IniProperties.loadIniFile() ;
			
			lastCfgFile = NLPStartup.getLastDataSet();
			if ((lastCfgFile==null) || (lastCfgFile.trim().length()<=1)){
				if (NLPStartup.getApplicationID().length()==0 ){
					NLPStartup.setApplicationID( this.getClass().getName().toLowerCase(),pubClass ) ;
				}
				
			}
			IniProperties.saveIniProperties() ;
			
			if (DFutils.fileExists(arguments.getConfigFile())==false){
				if ((arguments.getConfigFile().length()>0)){

					
					// lastCfgFile = IniProperties.dataSource ;
					if (arguments.getProjectName().length()==0){
						arguments.setProjectName ( "default") ;
					}
					
					fname = DFutils.createPath( arguments.getHomeDir(), arguments.getProjectName()+"/config/") ;
					fname = DFutils.createPath( fname, arguments.getConfigFile()) ;
					if (DFutils.fileExists(fname)){
						arguments.setConfigFile (fname);
					}else{
						if (fileutil.filenameIsUsable(fname)){
							arguments.setConfigFile (fname);
						}
					}
				}
				
				
				
				if (DFutils.fileExists(arguments.getConfigFile())==false){

					// this takes the internal resources and creates an external file from it
					
					createDefaultConfig();

					// we need not to stop in the iTexx context
					if (arguments.getContextMode().contentEquals(InstanceProcessControlIntf._APP_CONTEXT_ITEXX)==false){
						String msgstr = "you now have to edit the configuration file : \n" +
						                 "  " + arguments.getConfigFile();
						NLPStartup.showMsg(msgstr);

						// DocoServStartup.introduceDataSet(
						// arguments.configFile ) ;

						IniProperties.saveIniProperties();
						// copy the filename to the system clipboard
						System.exit(11);
					}

				}else{
					
				}
				
			}
			
			IniProperties.saveIniProperties() ;
			
			_showCurrentInputSettings();
			
			
			fname=fname+" " ;
			
		} catch (Exception e) {
			e.printStackTrace();
		}

		
		
	}
	

	public void close() {
		// TODO Auto-generated method stub
		lingInstance.close(1) ;
	}


	private void createDefaultConfig() throws Exception {
		 
		String filename = "", filstr,resourcePath;
		boolean rB;

		resourcePath = "org/NooLab/openNLP/app/resources/nlp-config-xml" ;
		ResourceLoader rsrcLoader = new ResourceLoader();   
		
		rB = rsrcLoader.loadTextResource( this.getClass(), resourcePath  ) ;
		if (rB){  
			filstr = rsrcLoader.getTextResource();
			
			filename = arguments.getConfigFile() ;
			
			fileutil.manageBakFile(filename, 10);
			fileutil.writeFileSimple( filename , filstr);
			
		}else{
			throw(new Exception("unable to load resources (create-db-sql-xml) or \n"+
					            "to create a new configuration file : "+filename)) ;
		}


		
	}


	
	private void _showCurrentInputSettings(){
		String  pathitx="";
		
		if (arguments.getContextMode().contentEquals(InstanceProcessControlIntf._APP_CONTEXT_ITEXX) ){
			pathitx = "app/ling";
		}else{

			if (NLPStartup.isConfigAvailable(pathitx) == false) {

			}
		}
		out.print(1,"current project : "+ NLPStartup.getLastProjectName());
		 
	}


	
	public void go() {


		instanceStopped = false ;
		
		startEngines();
		
		PrintLog.Delay(2000) ;
		// we stop from the outside by writing a file "stop" to the config directory
		while ( instanceStopped == false){
			PrintLog.Delay(100) ;
		}
		lingInstance.close(0) ;

	}

	
	/**
	 * 
	 * @param somtype 0=default: simple, single run; 1=som optimizer
	 * @param lastProjectName2 
	 */
	private void startEngines(){
		
		if (lingInstance!=null){
			return;
		}

		out.print(1,"starting project <"+ IniProperties.lastProjectName+"> ...");
		
		// setting worktypes
		
		
		lingInstance = new LinguisticProcessorInstance( this );
		
		if (arguments!=null){
			lingInstance.contextMode = arguments.getContextMode() ;
			
			lingInstance.homedir      = (String)arguments.getMappedTopic("homeDir");
			lingInstance.projectname  = (String)arguments.getMappedTopic( new String[]{"project","prj","proj"});

			lingInstance.logLevel     = (Integer)arguments.getMappedTopic("loglevel");
			
			lingInstance.onCompletion = (String)arguments.getMappedTopic("oncompletion"); 
						  
			lingInstance.flavor       = (String)arguments.getMappedTopic("flavor");
			
			
			
			lingInstance.appSecret    = (String)arguments.getMappedTopic("appsecret");
			
			lingInstance.processName  = (String)arguments.getMappedTopic("name");
			
			lingInstance.setArguments( arguments.getArgumentsObj());
			// this needs a simple tcp box...
		}
		
		boolean hb = lingInstance.checkForConfiguration();
		
		if (hb==false){
			lingInstance.close(-5);
		}
						int oport = arguments.getOutPort();
						int iport = arguments.getInPort();

		// is located in : org.NooLab.structures	
		lingInstance.prepareTcpBox(oport,iport);  // must be before the wait object !
		
		if ((lingInstance.contextMode.toLowerCase().contentEquals("itexx")) &&
			(lingInstance.waitfor>=1)){
			// waitfor-secret for testing is "adkhf-23487asdf-3487sdfr-324"
			out.print(2, "Application will wait a few seconds for final clearance...");
			lingInstance.waitfor();
		}
		
		
		// instance will check whether it could resume...
		lingInstance.startInstance() ;
		
		while (lingInstance.isRunning()){
			PrintLog.Delay(500);
		}
	}

	
}




@SuppressWarnings("rawtypes")
/*
-homedir:"D:/data/iTexx/app/ling" 
-context:itexx
-comm: in-7205,out-7206
-name:itexxwin
-loglevel:2




 */
class Arguments extends ArgumentsCliReaderAbstract implements ArgumentsIntf {
	
	public final String _APP_COMPLETION_EXIT    = InstanceProcessControlIntf._APP_COMPLETION_EXIT ;
	public final String _APP_COMPLETION_SERVICE = InstanceProcessControlIntf._APP_COMPLETION_SERVICE ;
	
	public final String  _APP_CONTEXT_ITEXX = InstanceProcessControlIntf._APP_CONTEXT_ITEXX ;
	public final String  _APP_CONTEXT_ALONE = InstanceProcessControlIntf._APP_CONTEXT_ALONE ;
	

	String sourceFileDedicated="",sourceFilesByFolder="",sourceFileByListingFile="";
	
	protected ArgumentsPublicIntf arguments ;
	public Map argumentsMap;
	
	
	
	// ------------------------------------------------------------------------
	@SuppressWarnings("unchecked")
	public Arguments(){
		super();
		setParent( this ) ;
		
		//default = standalone
		contextMode = InstanceProcessControlIntf._APP_CONTEXT_ALONE ; // itexx or standalone, running user based projects	
	}
	// ------------------------------------------------------------------------

	// preparation of arguments and stable parts of the set of arguments 
	// is outsourced to the abstract class
	// else the basic parts of the check are presented in a more convenient way
	
	@SuppressWarnings("unchecked")
	@Override
	public ArgumentsPublicIntf parse( String[] _args ){
		
		String avStr, str;
		
		
		// jarDir = fileutil.getUserDir();
		str = fileutil.getUserHomeDir() ;
		str = IniProperties.fluidSomProjectBasePath; // before, we passed readbinpref() !
		homeDir = DFutils.createPath( str, "app/ling/") ;
		
		LogControl.Level=2;
		
		defineArguments( new String[]{ "prj","homedir","cfg","sourcemode",
				                       "onCompletion","name","comm",
				                       "context","flavor",
				                       "loglevel"});
		
		try {
			String filename="";
			
			if ((_args==null) || (_args.length==0)){
				filename = "NooLabNLP.clia";
				
				if (str.indexOf("/bin")>0){
					filename = DFutils.createPath(str , filename);
				}else{
					filename = DFutils.createPath(str , "bin/"+filename);
				}

				if (DFutils.fileExists(filename)){
					_args = strgutil.changeArrayStyle( (fileutil.readFileintoVectorstringTable(filename)) );
					
				}
			}

PrintLog.Print(1, "path for clia : "+filename);		
PrintLog.Print(1, "received args : "+ strgutil.arr2text(_args, "", "  "));

			arguments = prepareArguments( homeDir, _args ) ;

		} catch (Exception e) {
			showArguments( getDescription() );
			System.exit(91);			
		}  
		
		argumentsMap = getArgumentsMap();
		
		
		if (handlingTreatment( new String[]{"flavor"})){

			String fstr = (String)getMappedTopic( new String[]{"flavor"} );
			ValuePair bagField = new ValuePair("flavor",fstr);
			fieldBag.add(bagField) ; 
			
			// this.setFlavor(flavor = fstr );
			
			
		}
		if (handlingTreatment( new String[]{"prj","proj","project"})){
		
			projectName = (String)getMappedTopic( new String[]{"prj","proj","project"} );
			
			
			NLPStartup.setLastProjectName(projectName);
			IniProperties.lastProjectName = projectName;
			
			str = IniProperties.getFluidSomProjectBasePath() ;
			if (IniProperties.getsBinPath().length()==0){
				
				str = (new PathFinder()).getAppBinPath(this.getClass(), false);
				IniProperties.setBinPath(str) ;
			}
			
			IniProperties.saveIniProperties();
			str = IniProperties.getFluidSomProjectBasePath() ;
		}
		
		int rn = remainingTopics.size();
		
		// the rest
		if (rn>0){
			for (int i=0;i<rn;i++){
				String topic = (String) remainingTopics.get(i); 
				avStr = getArgumentValueStr( new String[]{topic} );
				if (avStr.length()>0){
					
					if (topic.toLowerCase().contentEquals("startsomclients")){
						// -startSomClients:1,7211,7210
						String[] scs = avStr.split(",") ;
						if (scs.length==3){
							if (strgutil.isNumericX(scs[0])){
								startSomClients = strgutil.getNumFromStr(scs[0], 0);
							}
							int portnum = 1;
							if (strgutil.isNumericX(scs[1])){
								portnum = strgutil.getNumFromStr(scs[1], 0);
								if (portnum>1090){
									inPort = portnum;  
								}
							}  
							if (strgutil.isNumericX(scs[2])){
								portnum = strgutil.getNumFromStr(scs[2], 0);
								if (portnum>1090){
									outPort = portnum;
								}
								
							}
						}
					}
				}// sth found
			}//i->
		}
		
		if (_args.length==0){
			showArguments( getDescription() );
			System.exit(12);
		}
		
		if (defaultsRequested){
			
			homeDir     = fileutil.createpath( fileutil.getUserDir(), "ling") ;
			projectName = "itexx" ;
			configFile  = fileutil.createpath( homeDir, "nlp-config.xml") ;
			// this file will be read by DocoControlProperties.readSettings()
		}
		
				
				
		setReference( (Object)this);
		return (ArgumentsPublicIntf) this;
	}
	

	
	/*
		-prj:"test2"
		-homedir:"D:/data/iTexx/DocumentServer"
		-cfg:"D:/data/iTexx/DocumentServer/test1/config/docoserv-config.xml"
	 */

	
	

	public boolean startApplet() {
		return appletRequested;
	}

	
	@Override
	public String get_APP_COMPLETION_EXIT() {
		return _APP_COMPLETION_EXIT;
	}

	@Override
	public String get_APP_COMPLETION_SERVICE() {
		return _APP_COMPLETION_SERVICE;
	}

	@Override
	public String get_APP_CONTEXT_ITEXX() {
		return _APP_CONTEXT_ITEXX;
	}

	@Override
	public String get_APP_CONTEXT_ALONE() {
		return _APP_CONTEXT_ALONE;
	}

	public ArgumentsPublicIntf getArguments() {
		return arguments;
	}

	@Override
	public String[] getDescription() {
		String[] dParts = new String[3];
		 
		
		dParts[0] = "Values (examples) appear subsequent to the : \n"+
		        	"-prj:\"test2\"  \n"+
		        	"-homedir:\"D:/data/iTexx/app/ling\" \n"+
		        	" \n" ;

		dParts[1] = "Default values are activated by parameter \"-default\" or \"-d\" and are set to: \n"+
			        "-prj: docoserv  \n"+
					"-homedir: <path of jar>/DocumentServer \n"+
					"\n";
		
		
		dParts[2] = "Additional Information: \n"+
		      "- The database file will be written to the folder \"<homedir>/<project name>/storage\".  \n"+
		      "- If no configuration file has been provided, a default file will be created into \n" +
		      "  the folder \"<homedir>/<project name>/config\". \n"+
		      "  Note that you then have to edit the configuration file, namely the section defining the \n"+
		      "  the folders to be observed.\n"+
		      "- You may stop the application by creating a file \"stop\" within the folder containing \n"+
		      "  the configuration file.  \n"+
		      "- The parameters for activating the notification are port numbers, (1) in, (2) out, where \n"+
		      "  the in-port allows for some udimaentary control, such like stopping the application, or \n"+
		      "  re-reading the configuration. \n"+
		      "- For starting the interactive applet version (e.g. for testing) use the \n"+
		      "  parameter \"-a\" or \"-applet\" \n\n"+" ";
		
		
		return dParts;
	}

	@Override
	public int[] getPorts() {
		return ports;
	}

	@Override
	public int[] getServicePorts() {		
		return servicePorts ;
	}

	@Override
	public String getAppSecret() {
		return appsecret;
	}



	
}


class LinguisticProcessorInstance extends AppInstanceAbstract{
  
	
	public String flavor;
	NlpFactory nlpFactory;
	LinguistProperties lpProperties;
	
	
	int instanceType;
	int nodeCount = 400;
	
	App app;
	private String nlpFlavor ="";
	private boolean isRunning;
	private int aliveCheckc=0;;
	
	
	// ========================================================================
	public LinguisticProcessorInstance(App app){
		
		// these two string values are just for convenience of console output, 
		// it is not used by the application itself for any control
		super( "NlpApp", "");
		
		processName = "nlp";
		
		this.app = app;
		
		instance = this;
		out = app.out ;
	}
	// ========================================================================
	
	public boolean isRunning() {
		// 
		
		aliveCheckc++;
		
		if ((nlpFactory!=null) && (nlpFactory.nlp!=null)){
			isRunning = nlpFactory.nlp.isActive();
			aliveCheckc = 0;
		}else{
			if (aliveCheckc<5){
				isRunning = true;
			}else{
				isRunning = false;
			}
		}
			
		return isRunning ;
	}


	
	protected void setNodeCount(int nodecount) {
		
		if (nodecount>25){
			nodeCount = nodecount;
		}
	}


	protected void startInstance() {
		
		appSecret = app.arguments.getAppSecret() ;
		
		instanceThrd.start();
	}
	
	@Override
	public void close(int exitcode) {
		
		nlpFactory.close();
		
		super.close(2) ;
	}

	protected void resume() {
		// 
		
		resumeMode = checkForPossibleResuming();
		instanceThrd.start();
	}


	private boolean checkForPossibleResuming() {
		
		return false;
	}
	
	protected boolean checkForConfiguration() {
		// 
		return true;
	}
	
	




	protected void prepareInstance() {

			
		
		// this might be called with some URL or xml-string that represents the source containing the settings
		// if this exists, it will be loaded
		
		lpProperties = LinguistProperties.getInstance(); 
		
		
		lpProperties.setApplicationContext(contextMode);
		
		
		// dir = fileorg.getObjectStoreDir(pathitx)
		
		if (DFutils.folderExists(lpProperties.getSystemRootDir())==false){
			lpProperties.setSystemRootDir( IniProperties.fluidSomProjectBasePath );
		}

		NLPStartup.setLastProjectName(projectname); 
		NLPStartup.setProjectBasePath(homedir);
		NLPStartup.setLastProjectName(projectname); 
		NLPStartup.setProjectBasePath(homedir);

		lpProperties.getPersistenceSettings().setProjectName(projectname);
		lpProperties.getPersistenceSettings().setAppNameShortStr("nlp");
		lpProperties.getPersistenceSettings().setPathToSomFluidSystemRootDir( lpProperties.getSystemRootDir() );
		lpProperties.getFileOrganizer().setRootDir( lpProperties.getSystemRootDir() );
		lpProperties.getFileOrganizer().setProjectDirName(DFutils.createPath(homedir, projectname)) ;
		lpProperties.getFileOrganizer().setProjectBaseDir(homedir);
		
		lpProperties.setApplicationHomeDir(this.homedir);
		
		lpProperties.setActivateForSearchTerms(true) ;
		
		/*
		org.NooLab.somfluid.app.up.IniProperties = new IniProperties( IniProperties.fluidSomProjectBasePath,
				   													  IniProperties.lastProjectName,
				   													  IniProperties.dataSource);
											 // _projectBasePath,_lastProjectName, _dataSource
	    */
		
		explicitlySettingProperties();
		
		lpProperties.setActivateForSearchTerms(true) ;
		
		lpProperties.setOnCompletion( onCompletion );
		
		String str="";
		if (flavor.indexOf(",")>0){
			String[] fstr = flavor.split(",");
			str = fstr[1];
		}else{
			str=flavor;
		}
		lpProperties.setActiveLanguage(str);
		
		nlpFactory = NlpFactory.get(lpProperties);					   // creating the factory; calling without "factorymode" parameter, optimizer will be assumed	
		 
		nlpFactory.setTcpBox( getTcpBox() );
		
		nlpFactory.saveStartupTrace( nlpFlavor,  
									 lpProperties.getStartupTraceInfo() );
		lpProperties.save();
		
		
					int oport = app.arguments.getOutPort();
					int iport = app.arguments.getInPort();
		
		
		str = lpProperties.getApplicationContext() ;
		
		try {
			
			nlpFactory.go( );

							
		} catch (Exception e) {
			e.printStackTrace();
		}          		
		
		str = str + " " ;
	}
 
	


	private void explicitlySettingProperties(){
		
		 
		PersistenceSettings ps;
		 

		String str, dbDefinitionResource="" ;
		
		try {
			
			
			String instance = "ling";
			
			lpProperties.setFlavor( "") ; // describes on language and functinoality

			// -------------------------------------------------------------------------------
			
			// "file", "db", "tcp"
			lpProperties.setDataSourcing( DataStreamProviderIntf._DSP_SOURCED_TCP ,0) ;
			// lpPropertiesDefaults.setDataSourcing( DataStreamProviderIntf._DSP_SOURCED_FILE ,0) ;
			
			lpProperties.setDataSourceName( IniProperties.dataSource );
			
			
			
			 
			// -------------------------------------------------------------------------------
			
			/*
			 * 
			 
			// optional, if there are indeed plugin files ...
			// dependent on appcontext
			if (lpProperties.isITexxContext()){
				
											out.print(2, "context detected : itexx");				
				str = lpProperties.getSystemRootDir();
											out.print(4, "system root (1): "+str);				
				if (str.length()==0){
					
					lpProperties.setSystemRootDir( IniProperties.fluidSomProjectBasePath) ;
					str = lpProperties.getSystemRootDir();    // D:/data/iTexx/  ... it is empty when started by iTexx
											out.print(4, "system root (2): "+str);				
					if (str.length()==0){
						str = DFutils.getParentDir(homedir, 2);
						lpProperties.setSystemRootDir( str) ; // D:/data/iTexx/app/ling
						str = lpProperties.getSystemRootDir();
											out.print(4, "system root (3): "+str);				
					}
											out.print(4, "system root (4): "+str);						
				}
				 
				// later, we may allows plug-ins
				str = DFutils.createPath( lpProperties.getSystemRootDir(), "app/ling/plugins/") ;
						out.print(4, "system root + partial algo path : "+str);				
				lpProperties.setAlgorithmsConfigPath( str );
			}else{
				lpProperties.setAlgorithmsConfigPath( "D:/dev/java/somfluid/plugins/" );
			}
			
			*/
			 
			str = lpProperties.getSystemRootDir() ;
			str = IniProperties.fluidSomProjectBasePath;
			
			if (lpProperties.isITexxContext()==false){
				lpProperties.setSystemRootDir(str) ;
			}
			
			
			lpProperties.setMultiProcessingLevel(0); 
			
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("NLP, explicitlySettingProperties(): The system will exit.\n"+e.getMessage());
			System.exit(-7) ;
		}
		
		// --- --- ---

		/*
		 * in this folder there will be enumerated sub-folders containing the results
		 */
		String resultFolder ;


		// set ready flag
		lpProperties.setInitializationOK(true) ;						
	}
	 

	@Override
	protected void resumeInstance() throws Exception {
	}



	
}



